﻿namespace XGameLibrary.ScreenManager
{
    using System;
    using System.Collections.Generic;

    using Microsoft.Xna.Framework;

    public class GameStateManager : GameComponent
    {
        private const int StartDrawOder = 5000;
        private const int DrawOrderInc = 100;

        public GameStateManager(Game game)
            : base(game)
        {
            this.DrawOrder = GameStateManager.StartDrawOder;
            this.GameStates = new Stack<GameState>();
        }

        public event EventHandler OnStateChange;

        public GameState CurrentState
        {
            get { return this.GameStates.Peek(); }
            set { this.CurrentState = value; }
        }

        private int DrawOrder { get; set; }

        private Stack<GameState> GameStates { get; set; }

        public void PopState()
        {
            if (this.GameStates.Count > 0)
            {
                this.RemoveState();
                this.DrawOrder -= GameStateManager.DrawOrderInc;

                if (this.OnStateChange != null)
                {
                    this.OnStateChange(this, null);
                }
            }
        }

        public void PushState(GameState newState)
        {
            this.DrawOrder += GameStateManager.DrawOrderInc;
            newState.DrawOrder = this.DrawOrder;

            this.AddState(newState);

            if (this.OnStateChange != null)
            {
                this.OnStateChange(this, null);
            }
        }

        public void ChangeState(GameState newState)
        {
            while (this.GameStates.Count > 0)
            {
                this.RemoveState();
            }

            newState.DrawOrder = GameStateManager.StartDrawOder;
            this.DrawOrder = GameStateManager.StartDrawOder;

            this.AddState(newState);

            if (this.OnStateChange != null)
            {
                this.OnStateChange(this, null);
            }
        }

        private void AddState(GameState newState)
        {
            this.GameStates.Push(newState);

            this.Game.Components.Add(newState);

            this.OnStateChange += newState.StateChange;
        }

        private void RemoveState()
        {
            var state = this.CurrentState;

            this.OnStateChange -= state.StateChange;
            this.Game.Components.Remove(state);
            this.GameStates.Pop();
        }
    }
}
